/*
    异步写入模块缓存区
*/

#ifndef __M_BUFFER_H__
#define __M_BUFFER_H__
#include"util.hpp"
#include<vector>
#include<cassert>

namespace Hxy_Log
{
    #define BUFFER_MAX_SIZE 1*1024*1024
    #define THRESHOLE_BUFFER_SIZE 8*1024*1024  //最大阈值前倍数增长
    #define INCREAM_BUFFER_SIZE 1*1024*1024    //线性增长
    class Buffer
    {
        public:
            Buffer():_buffer(BUFFER_MAX_SIZE),_reader_ptr(0),_write_ptr(0){}
            //向缓存区写入数据
            void push(const char* data,size_t len)
            {
                //扩容
                ensureEnoughtSize(len);
                //1.数值拷贝
                std::copy(data,data+len,&_buffer[_write_ptr]);
                //2.移动可写入指针
                moveWrite(len);
            }
            //返回可读数据的起始地址
            const char* begin()
            {
                return &_buffer[_reader_ptr];
            }
            //返回可读数据的长度
            size_t readableSize()
            {
                //当前缓存区是双缓冲区设计思想，只会一直往后写，不存在循环队列的情况
                return (_write_ptr - _reader_ptr);
            }
            //返回可写数据的长度
            size_t writeableSize()
            {
                //对于扩容来说不需要查看可写大小，只针对固定缓存区大小
                return (_buffer.size() - _write_ptr);
            }
            //对读写指针向后偏移
            void moveRead(size_t len)
            {
                assert(len <= readableSize());
                _reader_ptr+=len;
            }
            //重置读写位置，初始化缓存区
            void reset()
            {
                _reader_ptr = _write_ptr = 0;
            }
            //对buffer进行做交换
            void swap(Buffer& buffer)
            {
                _buffer.swap(buffer._buffer);
                std::swap(_write_ptr,buffer._write_ptr);
                std::swap(_reader_ptr,buffer._reader_ptr);
            }
            //判断缓存区是否为空
            bool empty()
            {
                return _write_ptr == _reader_ptr;
            }
        private:
            void ensureEnoughtSize(size_t len)
            {
                if(len <= writeableSize()) return;   //不需要写入的情况
                size_t buffersize =0;
                if(_buffer.size() <= THRESHOLE_BUFFER_SIZE)
                {
                    //+len防止len过打*2后还是小于len的情况
                    buffersize = _buffer.size()*2 + len;   //进行倍速增长
                }
                else{
                    buffersize = _buffer.size()+INCREAM_BUFFER_SIZE+len;//进行线性增长
                }
                _buffer.resize(buffersize);
            }
            void moveWrite(size_t len)
            {
                assert((_write_ptr+len) <= _buffer.size());
                _write_ptr+=len;
            }
        private:
            std::vector<char> _buffer;  
            size_t _reader_ptr; //当前能够读位置的指针
            size_t _write_ptr;  //当前能够写位置的指针
    };
}
#endif